﻿//******************************************************************************************************
//  FrequencyAnalyst.cs - Gbtc
//
//  Copyright © 2010, Grid Protection Alliance.  All Rights Reserved.
//
//  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
//  the NOTICE file distributed with this work for additional information regarding copyright ownership.
//  The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
//  not use this file except in compliance with the License. You may obtain a copy of the License at:
//
//      http://www.opensource.org/licenses/eclipse-1.0.php
//
//  Unless agreed to in writing, the subject software distributed under the License is distributed on an
//  "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
//  License for the specific language governing permissions and limitations.
//
//  Code Modification History:
//  ----------------------------------------------------------------------------------------------------
//  09/30/2010 - Stephen C. Wills
//       Generated original version of source code.
//
//******************************************************************************************************

using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using TestBenchApi;
using TVA.PhasorProtocols;

namespace TestBenchAnalyst
{
    /// <summary>
    /// An analyst that determines whether the frequency values
    /// in the source frames match those of the received frames.
    /// </summary>
    public class FrequencyAnalyst : Analyst
    {

        #region [ Members ]

        // Fields

        private string m_frequencyFilePath;
        private TextWriter m_frequencyFileWriter;
        private bool m_allMatch;

        #endregion

        #region [ Methods ]

        /// <summary>
        /// Initializes the <see cref="FrequencyAnalyst"/>.
        /// </summary>
        /// <param name="packageFilePath">The path to the package file.</param>
        public override void Initialize(string packageFilePath)
        {
            base.Initialize(packageFilePath);

            string outputFile = PackageFile.Receiver.OutputFile;
            m_frequencyFilePath = outputFile.Substring(0, outputFile.LastIndexOf('.')) + " - frequency.csv";
        }

        /// <summary>
        /// Occurs when the analyst is started.
        /// </summary>
        protected override void OnAnalystStarted()
        {
            base.OnAnalystStarted();
            m_allMatch = true;
            m_frequencyFileWriter = new StreamWriter(File.Create(m_frequencyFilePath));
        }

        /// <summary>
        /// Occurs when the analyst is stopped.
        /// </summary>
        protected override void OnAnalystStopped()
        {
            base.OnAnalystStopped();

            if (m_frequencyFileWriter != null)
            {
                if (m_allMatch)
                    m_frequencyFileWriter.WriteLine("All source frequencies match received frequencies.");

                m_frequencyFileWriter.Close();
            }
        }

        /// <summary>
        /// Compares the frequency values stored in the frames.
        /// </summary>
        /// <param name="sourceFrame">The original frame sent by the generators.</param>
        /// <param name="receivedFrame">The corresponding frame as received by the receiver.</param>
        /// <param name="timeReceived">The time at which the frame was received by the receiver.</param>
        public override void CompareFrames(IDataFrame sourceFrame, IDataFrame receivedFrame, long timeReceived)
        {
            // Frequencies of missing frames cannot be
            // compared so we don't even try.
            if (receivedFrame != null)
            {
                IEnumerable<double> srcFrequencies = sourceFrame.Cells.Select(cell => cell.FrequencyValue.Frequency);
                IEnumerable<double> recFrequencies = receivedFrame.Cells.Select(cell => cell.FrequencyValue.Frequency);
                IEnumerable<double> distinctFrequencies = srcFrequencies.Union(recFrequencies);

                if (distinctFrequencies.Count() > 1)
                {
                    StringBuilder line = new StringBuilder();

                    // If this is the first occurrence of frequencies that don't match,
                    // we must place the header in the frequency file.
                    if (m_allMatch)
                    {
                        StringBuilder header = new StringBuilder("Timestamp,");

                        // Add entries for the cells in the source frames to the header.
                        for (int ctr = 1; ctr <= sourceFrame.Cells.Count; ctr++)
                        {
                            header.Append("Source Cell ");
                            header.Append(ctr);
                            header.Append(',');
                        }

                        // Add entries for the cells in the received frames to the header.
                        for (int ctr = 1; ctr <= receivedFrame.Cells.Count; ctr++)
                        {
                            header.Append("Received Cell ");
                            header.Append(ctr);
                            header.Append(',');
                        }

                        // Remove the extra comma and write the header to the file.
                        header.Remove(header.Length - 1, 1);
                        m_frequencyFileWriter.WriteLine(header.ToString());
                    }

                    // Add the frame timestamp to the line.
                    line.Append(sourceFrame.Timestamp);
                    line.Append(',');

                    // Add the frequencies in the source frame to the line.
                    foreach (double srcFrequency in srcFrequencies)
                    {
                        line.Append(srcFrequency);
                        line.Append(',');
                    }

                    // Add the frequencies in the received frame to the line.
                    foreach (double recFrequency in recFrequencies)
                    {
                        line.Append(recFrequency);
                        line.Append(',');
                    }

                    // Remove the trailing comma and write the line to the file.
                    line.Remove(line.Length - 1, 1);
                    m_frequencyFileWriter.WriteLine(line.ToString());
                    m_allMatch = false;
                }
            }
        }

        #endregion
    }
}
